home *** CD-ROM | disk | FTP | other *** search
- /*
- * Blob Manager Demonstration: Wolf & Goats module
- *
- * This is played on a checkerboard. The wolf starts in one corner,
- * the four goats on the opposite row. All moves are into adjoining
- * diagonal squares. The wolf can move forward or backward, the goats
- * only forward. The goats try to trap the wolf so he can't move,
- * while the wolf tries to get past the goats to the other side.
- *
- * This game is a variant of fox & geese.
- *
- * 1 August 1986 Paul DuBois
- *
- * 24 Dec 93
- * - First two arguments to DrawBoardPos() were reversed.
- * - Changed DrawBoardPos() to use RGB gray for dimmed positions when
- * possible.
- */
-
- # include "TransSkel.h"
-
- # include "BlobMgr.h"
- # include "BlobDemo.h"
-
-
- # define rows 8 /* number of rows on board */
- # define columns 8 /* number of columns on board */
- # define pieceSize 20 /* size of each piece */
- # define vMessage 165 /* vertical position of message */
-
- # define BoardPos(b,ph,pv) FindCheckerBoardPos(b,&board,ph,pv)
- # define PosEmpty(h,v) CheckerBoardPosEmpty(&board,h,v)
- # define PosFilled(h,v) CheckerBoardPosFilled(&board,h,v)
-
-
- static WindowPtr wind;
-
- static BlobSetHandle boardBlobs = nil;
- static CheckerBoard board;
- static BlobSetHandle donors = nil;
- static BlobHandle wolf;
- static BlobHandle goat;
- static BlobHandle current;
- static BlobSetHandle misc;
- static BlobHandle resetBlob; /* simulated control */
- static short hWolf;
- static short vWolf;
-
- static short hMid;
- static Boolean pause;
- static Str255 statusStr = "\p";
-
-
- static void
- StatusMesg (StringPtr s)
- {
- Rect r;
-
- SetRect (&r, 0, vMessage, wind->portRect.right - 25, vMessage + 12);
- TextBox (s+1, (long) s[0], &r, teJustCenter);
- StrCpy (statusStr, s);
- }
-
-
- /*
- * Set the board to the initial configuration
- */
-
- static void
- Reset (void)
- {
- short i;
-
- UnglueGlobSet (boardBlobs); /* clear all globs */
- GlueGlob (wolf, board[hWolf = 0][vWolf = 0]);
- for (i = 1; i < columns; i += 2)
- GlueGlob (goat, board[i][rows - 1]);
- current = wolf;
- StatusMesg ("\pWolf's Move");
- pause = false;
- }
-
-
- static void
- WolfPause (StringPtr msg)
- {
- StatusMesg (msg);
- pause = true;
- }
-
-
- /*
- * Test whether a piece can move or not. The goats can only move
- * forward (which for them means to a lower-numbered row), while the
- * wolf can move forward or backward.
- */
-
- static Boolean
- CanMove (short h, short v)
- {
- BlobHandle g;
-
- g = BGlob (board[h][v]);
- if (g == goat && v == 0)
- return (false); /* goats can't move from row zero */
- return (PosEmpty (h - 1, v - 1)
- || PosEmpty (h + 1, v - 1)
- || (g == wolf
- && (PosEmpty (h - 1, v + 1)
- || PosEmpty (h + 1, v + 1))));
- }
-
-
- static pascal void
- Mouse (Point pt, long t, short mods)
- {
- Str255 s;
- short i;
-
- if (TestBlob (resetBlob, pt))
- {
- if (BTrackMouse (resetBlob, pt, inFullBlob))
- Reset ();
- }
- else if (!pause)
- {
- BlobClick (pt, t, nil, boardBlobs);
- if (BClickResult () == bcXfer)
- {
- if (!CanMove (hWolf, vWolf)) /* wolf locked in? */
- WolfPause ("\pGoats Win");
- else if (vWolf == rows - 1) /* wolf made it */
- WolfPause ("\pWolf Wins");
- else
- {
- current = (current == wolf ? goat : wolf);
- StatusMesg (current == wolf ?
- "\pWolf's Move" : "\pGoats' Move");
- }
- }
- }
- }
-
-
- /*
- * When a piece is clicked on, the advisory checks whether the piece has
- * any legal moves available to it. If so, it returns true, so that
- * BlobClick is allowed to drag the piece. After the piece has been
- * dragged, the advisory checks whether the position it was dragged to
- * is legal, and returns true if so.
- *
- * Messages passed to the advisory follow the pattern
- *
- * { { advRClick advRClick* } advXfer* }*
- *
- * where * means 0 or more instances of the thing *'ed. In particular,
- * the advXfer message is never seen without a preceding advRClick.
- */
-
- static pascal Boolean
- Advisory (short mesg, BlobHandle b)
- {
- static short h, v; /* static to save board position of click on piece */
- short h2, v2;
- Boolean result;
-
- switch (mesg)
- {
-
- case advRClick: /* first click on piece */
- if (BGlob (b) != current)
- return (false); /* can only move current piece(s) */
- BoardPos (b, &h, &v); /* find where it is */
- return (CanMove (h, v));
-
- case advXfer: /* Mouse released after dragging piece */
-
- BoardPos (b, &h2, &v2);
- result = ((h2 == h - 1 && v2 == v - 1)
- || (h2 == h + 1 && v2 == v - 1)
- || (current == wolf
- && ((h2 == h - 1 && v2 == v + 1)
- || (h2 == h + 1 && v2 == v + 1))));
- if (result == true && current == wolf)
- {
- hWolf = h2; /* update wolf's position */
- vWolf = v2;
- }
- return (result);
- }
- }
-
-
- static pascal void
- Update (Boolean resized)
- {
- DrawBlobSet (boardBlobs);
- DrawBlob (resetBlob, inFullBlob);
- StatusMesg (statusStr);
- }
-
-
- /*
- * Activate the window: Set the advisory function and set the permissions
- * to transfer-only. Clear, replace, duplication and swap are off.
- * Since replace is off, the advisory doesn't have to check whether
- * the dragged piece was dragged onto a blob that already has a glob.
- *
- * Deactivate the window: Clear the advisory.
- */
-
- static pascal void
- Activate (Boolean active)
- {
- if (active)
- {
- SetDragRects (wind);
- SetBCPermissions (false, true, false, false, false); /* xfer only */
- SetBCAdvisory (Advisory);
- }
- else
- {
- SetBCAdvisory (nil);
- }
- }
-
-
- void
- WolfInit (void)
- {
- Rect r;
-
- SkelWindow (wind = GetDemoWind (wolfWindRes),
- Mouse, /* mouse clicks */
- nil, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoWClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- hMid = wind->portRect.right / 2;
-
- donors = MakeCheckersPieces (pieceSize);
- wolf = GetBlobHandle (donors, 0);
- goat = GetBlobHandle (donors, 1);
- MakeCheckerBoard(&boardBlobs, &board, pieceSize);
-
- misc = NewBlobSet ();
- SetRect (&r, 0, 0, 20, 90);
- OffsetRect (&r, wind->portRect.right - 25,
- (wind->portRect.bottom - 90 - 25) / 2);
- resetBlob = NewVButtonBlob (misc, &r, "\pReset", true);
- Reset ();
-
- MakeFrontWind (wind);
- }
-